-- 需要注意的是，此库不应限制是否在世界中

local b_util = {}
local t_util = require "libs/tableutil"
local s_util = require "libs/settingmanager"
local e_util = require "libs/entutil"
local c_util = require "libs/calcutil"

--[[ 关于此表的维护说明
    此表会和数据存储的表数据合并，作为最终boss数据表，如果你填写此表的数据未生效，那么就是数据表覆盖了此表内容

    key, value
    key 作为一个倒计时的id, 会被相互覆盖
    value.prefabs 是主文件会监听的生物, 但当prefabs为空时, prefabs = {key}
    value.judge 是判定死亡的方式, 为空则生物消失时回调判定动画为death的函数, 为表时则检测表内动画
    一个生物相关监听都只会执行一次！注册时只保留首次！
    value.world 表示世界需要的tag，不存在此项 或 HasTag 时执行 appear 等函数
    value.appear 表示生物出现时回调的函数，不存在或返回真时通知 boss已生成
    value.death 表示生物出现死亡状态时回调的函数，不存在或返回真时通知 boss已死亡

    必填项目
    id = {
        image, duration, descripe
    }


    测试代码：
    e_util = require "libs/entutil"
    e_util:SetBindEvent(nearEnt(), "onremove", function(e) print(e_util:GetAnim(e)) end)
]]--

local bosses_data = {
    dragonfly = {
        image = "chesspiece_dragonfly",
        duration = TUNING.DRAGONFLY_RESPAWN_TIME,
        descripe = STRINGS.NAMES.DRAGONFLY,
        death = function(e)
            return e_util:FindEnt(e, "lava_pond")
        end,
        world = "forest",
    },
    beequeen = {
        image = "chesspiece_beequeen",
        duration = TUNING.BEEQUEEN_RESPAWN_TIME,
        descripe = STRINGS.NAMES.BEEQUEEN,
        death = function(e)
            return e_util:FindEnt(e, "beequeenhive")
        end,
        world = "forest",
    },
    terrarium = {
        image = "terrarium_crimson",
        duration = TUNING.EYEOFTERROR_SPAWNDELAY,
        descripe = STRINGS.NAMES.TERRARIUM,
        prefabs = {"eyeofterror", "twinofterror1", "twinofterror2"},
        world = "forest",
        death = function(e)
            return not e_util:FindEnt(e, {"eyeofterror", "twinofterror1", "twinofterror2"})
        end,
    },
    malbatross = {
        image = "chesspiece_malbatross",
        duration = TUNING.MALBATROSS_SPAWNDELAY_BASE,
        descripe = STRINGS.NAMES.MALBATROSS,
        world = "forest",
        appear = function(e)
            return e:IsOnOcean(true)
        end
    },
    klaus = {
        image = "chesspiece_klaus",
        duration = TUNING.KLAUSSACK_EVENT_RESPAWN_TIME,
        descripe = STRINGS.NAMES.KLAUS,
        death = function(e)
            return e_util:FindEnt(e, "klaus_sack")
        end,
        world = "forest",
    },
    walrus = {
        image = "walrus_tusk",
        duration = TUNING.WALRUS_REGEN_PERIOD,
        descripe = STRINGS.NAMES.WALRUS,
        world = "forest",
    },
    crabking = {
        image = "chesspiece_crabking",
        duration = TUNING.CRABKING_RESPAWN_TIME,
        descripe = STRINGS.NAMES.CRABKING,
        world = "forest",
        appear = function(e)
            return e:IsOnOcean(true)
        end,
    },
    toadstool = {
        image = "chesspiece_toadstool",
        duration = TUNING.TOADSTOOL_RESPAWN_TIME,
        descripe = STRINGS.NAMES.TOADSTOOL,
        prefabs = {"toadstool", "toadstool_dark"},
        world = "cave",
        death = function(e)
            return e_util:FindEnt(e, "toadstool_cap")
        end,
    },
    -- 编制者死亡决定了两个事件：守护者的刷新（远古重置） 和 中庭的刷新
    minotaur = {
        image = "chesspiece_minotaur",
        descripe = STRINGS.NAMES.MINOTAUR,
        duration = TUNING.ATRIUM_GATE_DESTABILIZE_TIME + TUNING.ATRIUM_GATE_DESTABILIZE_WARNING_TIME,
        prefabs = {"stalker_atrium"},
        death = function(e)
            return e_util:IsAnim("idle_active", e_util:FindEnt(e, "atrium_gate"))
        end,
        world = "cave",
    },
    stalker_atrium = {
        image = "atrium_key",
        duration = TUNING.ATRIUM_GATE_COOLDOWN + TUNING.ATRIUM_GATE_DESTABILIZE_DELAY + TUNING.ATRIUM_GATE_DESTABILIZE_TIME + TUNING.ATRIUM_GATE_DESTABILIZE_WARNING_TIME,
        descripe = STRINGS.NAMES.STALKER_ATRIUM,
        world = "cave",
    },
    daywalker = {
        image = "chesspiece_daywalker",
        duration = TUNING.DAYWALKER_RESPAWN_DAYS_COUNT * TUNING.TOTAL_DAY_TIME,
        judge = {"defeat", "defeat_idle_pre"},
        descripe = STRINGS.NAMES.DAYWALKER,
        world = "cave",
        appear = function(e)
            return not e_util:IsAnim({"defeat_idle_loop"}, e)
        end
    },
}

local function onremove(ent)
    local anim = e_util:GetAnim(ent)
    return type(anim) == "string" and c_util:IsStrContains(anim, "death")
end

local pdata = {}
function b_util:LoadPrefabData()
    if next(pdata) then
        return pdata
    end
    local function setbossdata(prefab, data)
        pdata[prefab] = pdata[prefab] or {}
        local t = pdata[prefab]
        t.judge = t.judge or (data.judge or onremove)
        t.func_appear = t.func_appear or data.appear
        t.func_death = t.func_death or data.death
        -- t.func_remove = t.func_remove or data.disappear
        t.world_tag = t.world_tag or data.world
    end

    for b_id, b_data in pairs(bosses_data)do
        if type(b_data.prefabs) == "table" then
            for _, prefab in ipairs(b_data.prefabs)do
                setbossdata(prefab, b_data)
            end
        elseif type(b_id) == "string" then
            setbossdata(b_id, b_data)
        end
    end
    return pdata
end


function b_util:GetBoses(name)
    local bdata = {}

    for b_id, b_data in pairs(bosses_data)do
        if (b_id == name) or (type(b_data.prefabs) == "table" and table.contains(b_data.prefabs, name)) then
            bdata[b_id] = {
                image = b_data.image,
                altas = b_data.altas, 
                duration = b_data.duration,
                descripe = b_data.descripe,
            }
        end
    end

    return bdata
end
return b_util